﻿package bdz.common.effects
{
	import flash.display.*;
	import flash.events.*;
	import bdz.common.events.GenericEvent;
	
	/**
	 * ...
	 * @author ...
	 */
	public class BMPCrawler extends MovieClip 
	{
		private var copy:BitmapData;
		private var base:MovieClip;
		private var holder:Bitmap;
		private var queue:Array;
		private var maxnode:Number = 0;
		private var dmax:Number = 0;
		private var ptrigger:Array;
		private var firstrun:Boolean = true;
		
		public var id:Number;
		public var manual:Boolean = false;
		public var nodex:Number;
		public var nodey:Number;
		public var speed:Number = 4000;
		private var crawlAmount:Number = 3;
		
		function BMPCrawler(targ:MovieClip = null) {
			
			try {
				base = this["guide"];
			}catch (e:Error) {
				base = targ;
			}
			
			addEventListener(Event.ADDED_TO_STAGE, initialize);
		}
		private function initialize(evt:Event):void {
			
			ptrigger = new Array();
			queue = new Array();
			copy = new BitmapData(base.width, base.height, true, 0x00ffffff);
			copy.draw(base);
			parent.removeChild(base);
			
				
			
		}
		private function createHolder():void {
			try {
				if(holder){
					holder.bitmapData.dispose();
					removeChild(holder);
				}
			} catch (e:Error) {
			}
			holder = new Bitmap(new BitmapData(copy.width, copy.height, true, 0x00ffffff), "auto", true);
			addChild(holder);
		}
		private function checkPerimeter(sx:Number, sy:Number, amount:Number = 1):void {
			var stx:uint = sx-amount;
			var sty:uint = sy-amount;
			var base:uint = 1;
			base += (amount*2);
			var ex:uint = stx+base;
			var ey:uint = sty+base;
			while (stx < ex) {
				while (sty < ey) {
					queue.push({x:stx, y:sty});
					sty++;
				}
				stx++;
				sty = sy-amount;
			}
		}
		private function startCrawl():void {
			maxnode = 0;
			dmax = 0;
			addEventListener(Event.ENTER_FRAME, crawl);
		}
		private function applyPixels(nx:uint, ny:uint, c1:Number):void {
			checkTriggers(nx, ny);
			holder.bitmapData.setPixel32(nx, ny, c1);
			checkPerimeter(nx, ny, 1);
			firstrun = false;
		}
		private function createNodeAt(nx:uint, ny:uint):void {
			if (nx < 0 || ny < 0 || nx > copy.width || ny > copy.height) {
				return trace("pixel empty");
			}
			var c1:uint = copy.getPixel32(nx,ny);
			var c2:uint = holder.bitmapData.getPixel32(nx, ny);
			var base:Number = 1;
			if (c1 != 0 &&  c2 == 0) {
				applyPixels(nx, ny, c1);
				
			}else {
				if (firstrun) {
					removeEventListener(Event.ENTER_FRAME, crawl);
				}
			}
		}
		public function crawl(evt:Event = null):void {
			if (queue.length == 0) {
				queue = [];
				removeEventListener(Event.ENTER_FRAME, crawl);
				dispatchEvent(new GenericEvent(GenericEvent.COMPLETE));
			}
			maxnode = 0;
			var len:uint = speed;
			var qlen:uint = queue.length;
			
			for (var i:uint = 0; i < len; i++) {
				
				var rand:uint = Math.floor((Math.random()*len));
				var cnode:Object = queue.splice(rand, 1)[0];
				if (cnode) {
					maxnode++;
					
					createNodeAt(cnode.x, cnode.y);
				}
				cnode = null;
				
			}
			
			if(maxnode > dmax){
				dmax = maxnode;
			}
		}
		private function checkTriggers(tx:Number, ty:Number):void {
			if (ptrigger.length > 1){
				for each(var o:Object in ptrigger){
					if (o.tx == tx && o.ty == ty) {
						dispatchEvent(new GenericEvent("onTrigger", o));
						return;
					}
				}
			}else {
				if(ptrigger.length){
					o = ptrigger[0];
					if (o.tx == tx && o.ty == ty) {
						dispatchEvent(new GenericEvent("onTrigger", o));
						return;
					}
				}
			}
			
		}
		public function stopCrawl():void {
			try {
				removeEventListener(Event.ENTER_FRAME, crawl);
			}catch (e:Error) {
				
			}
		}
		public function addTrigger(obj:Object):void {
			
			ptrigger.push(obj);
			
		}
		public function startAt(x:Number, y:Number):void {
			
			
			try {
				removeEventListener(Event.ENTER_FRAME, crawl);
			}catch (e:Error) {
				
			}
			queue = [];
			createHolder();
			createNodeAt(x, y);
			if(!manual){
				startCrawl();
			}
			
		}
	}
	
}